﻿@page "/fetchaccounts"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using System.Net.Http.Headers
@using System.Net.Http.Json
@using Microsoft.Extensions.Logging
@using System.Text.Json.Serialization
@inject IAccessTokenProvider TokenProvider
@inject IHttpClientFactory ClientFactory
@inject ILogger<FetchAccounts> logger
@inject Models.AppState AppState
@implements IDisposable

<AuthorizeView>
    @*Only show the list if the user is signed in and authorized*@
    <Authorized>
        <h3>Fetch Accounts</h3>
        <br /><label>Selected Environment Url:  </label><a href="@AppState.SelectedEnvUrl.Replace(".api","")" target="_blank">@AppState.SelectedEnvUrl</a>

        @if (!string.IsNullOrEmpty(AppState.SelectedEnvUrl))
        {
            if (accounts != null)
            {
                <table class="table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Main Phone</th>
                            <th>City</th>
                            <th>Primary Contact</th>
                            <th>Email (Primary Contact)</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (Account account in accounts.value)
                        {
                            <tr id="@account.accountid">
                                <td>
                                    @((account.name != null)
                                ? account.name
                                : string.Empty)
                                </td>
                                <td>
                                    @((account.telephone1 != null)
                                ? account.telephone1
                                : string.Empty)
                                </td>
                                <td>
                                    @((account.address1_city != null)
                                ? account.address1_city
                                : string.Empty)
                                </td>
                                <td>
                                    @((account.primarycontactid != null)
                                ? (account.primarycontactid.fullname != null
                                    ? account.primarycontactid.fullname
                                    : string.Empty)
                                : string.Empty)
                                </td>
                                <td>
                                    @((account.primarycontactid != null)
                                ? (account.primarycontactid.emailaddress1 !=null
                                    ? account.primarycontactid.emailaddress1
                                    : string.Empty)
                                : string.Empty)
                                </td>
                            </tr>
                        }
                    </tbody>
                </table>
            }
            else
            {
                <p><em>@message</em></p>
            }
        }
        else
        {
            <p><em>Please select an environment</em></p>
        }

    </Authorized>
    <NotAuthorized>
        <h3>Authentication Failure!</h3>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>


@code {

    //The collection of Account records to display
    private AccountCollection accounts;

    //An informational message
    private string message = "Loading...";

    //Contains data about an error returned from the Web API
    private Error error;

    // Method invoked when the component is ready to start, having received its initial parameters from its parent in the render tree.
    // Override this method if you will perform an asynchronous operation and want the component to refresh when that operation is completed.
    protected override void OnInitialized()
    {
        AppState.OnChange += PopulateRecords;
        PopulateRecords();
    }

    async void PopulateRecords()
    {
        logger.LogInformation($"SelectedEnvUrl: {AppState.SelectedEnvUrl}");

        // Tries to get an access token for the current user with the default set of permissions.
        var tokenResult = await TokenProvider.RequestAccessToken(new AccessTokenRequestOptions
        {
            Scopes = new[] { $"{AppState.SelectedEnvUrl}/user_impersonation" }
        });

        // If the token request was successful
        if (tokenResult.TryGetToken(out var token))
        {
            //Creates an HttpClient based on the named definition found in Program.Main
            var client = ClientFactory.CreateClient("CDSClient");
            var baseAddress = !string.IsNullOrEmpty(AppState.SelectedEnvUrl) ? new Uri(AppState.SelectedEnvUrl + "/api/data/v9.1/") : client.BaseAddress;
            //Prepare the request to get the data

            var request = new HttpRequestMessage()
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri($"{baseAddress}accounts?" +
                "$select=name,telephone1,address1_city&" +
                "$expand=primarycontactid($select=fullname,emailaddress1)")
            };
            //Add the access token
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Value);
            //Specify a JSON result is expected
            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            //Limit the number of results to 10
            request.Headers.Add("Prefer", "odata.maxpagesize=10");

            //Send the request
            var response = await client.SendAsync(request);

            if (response.IsSuccessStatusCode)
            {
                //Parse the JSON returned into a strongly typed AccountCollection
                accounts = await response.Content.ReadFromJsonAsync<AccountCollection>();
            }
            else
            {
                //Parse the JSON returned into a strongly typed Error
                error = await response.Content.ReadFromJsonAsync<Error>();
                error.statuscode = (int)response.StatusCode;
                error.reason = response.ReasonPhrase;
                //Display a message to the user
                message = "An error occurred.";
                //Log the details so they can be seen in the browser console
                logger.LogError($"{error.detail.message}");

            }

        }
        else
        {
            // Notify user that the token request was not successful
            message = "There was a problem authenticating.";
        }

        this.StateHasChanged();
    }


    public void Dispose()
    {
        AppState.OnChange -= PopulateRecords;
    }

    // The result will be a JSON object with an array of entities set to the value property
    public class AccountCollection
    {
        public Account[] value { get; set; }
    }

    //Just the properties of the Account EntityType used for this sample
    // See https://learn.microsoft.com/dynamics365/customer-engagement/web-api/account
    public class Account
    {

        public Guid accountid { get; set; }

        public string name { get; set; }

        public string telephone1 { get; set; }

        public string address1_city { get; set; }

        public Contact primarycontactid { get; set; }

    }

    //Just the properties of the Contact EntityType that are expanded from the Account entity
    // See https://learn.microsoft.com/dynamics365/customer-engagement/web-api/contact
    public class Contact
    {

        public string fullname { get; set; }

        public string emailaddress1 { get; set; }
    }

    // Contains the error data returned by the Web API and the HttpMessageResponse
    public class Error
    {
        [JsonPropertyName("error")]
        public ErrorDetail detail { get; set; }
        public int statuscode { get; set; }
        public string reason { get; set; }

    }

    //Contains data from the Web API
    //See https://learn.microsoft.com/powerapps/developer/common-data-service/webapi/compose-http-requests-handle-errors#parse-errors-from-the-response
    public class ErrorDetail
    {
        public string code { get; set; }
        public string message { get; set; }

    }
}